//
//  YMNetworkUtil.swift
//  ChengLuMall
//
//  Created by 吳梓杭 on 2023/5/28.
//

import Foundation
import Moya
import SwiftyJSON

internal struct YMNetworkUtil {
    
    /// Read json data
    public static func jsonData(_ named: String, forResource: String = "RxNetworks") -> Data? {
        let bundle: Bundle?
        if let bundlePath = Bundle.main.path(forResource: forResource, ofType: "bundle") {
            bundle = Bundle.init(path: bundlePath)
        } else {
            bundle = Bundle.main
        }
        guard let path = ["json", "JSON", "Json"].compactMap({
            bundle?.path(forResource: named, ofType: $0)
        }).first else {
            return nil
        }
        let contentURL = URL(fileURLWithPath: path)
        return try? Data(contentsOf: contentURL)
    }

    /// 参数排序生成字符串
    static func sort(parameters: [String: Any]?) -> String {
        guard let params = parameters, !params.isEmpty else {
            return ""
        }
        var paramString = "?"
        let sorteds = params.sorted(by: { $0.key > $1.key })
        for index in sorteds.indices {
            paramString.append("\(sorteds[index].key)=\(sorteds[index].value)")
            if index != sorteds.count - 1 { paramString.append("&") }
        }
        return paramString
    }
    
    /// 处理配置插件
    static func handyConfigurationPlugin(_ plugins: APIPlugins,
                                         target: TargetType) -> ConfigurationTuple {
        var tuple: ConfigurationTuple
        tuple.result = nil
        tuple.endRequest = false
        tuple.session = nil
        plugins.forEach { tuple = $0.configuration(tuple, target: target, plugins: plugins) }
        return tuple
    }
    
    static func handyLastNeverPlugin(_ plugins: APIPlugins,
                                     result: MoyaResult,
                                     target: TargetType,
                                     onNext: @escaping (LastNeverTuple) -> Void) {
        var tuple: LastNeverTuple
        tuple.result = result
        tuple.againRequest = false
        tuple.mapResult = nil
        var iterator = plugins.makeIterator()
        func handleLastNever(_ plugin: YMPluginSubType?) {
            guard let _plugin = plugin else {
                onNext(tuple)
                return
            }
            _plugin.lastNever(tuple, target: target) { __tuple in
                tuple = __tuple
                handleLastNever(iterator.next())
            }
        }
        handleLastNever(iterator.next())
    }
    
    @discardableResult
    static func beginRequest(_ api: YMTargetType,
                             base: MoyaProvider<MultiTarget>,
                             queue: DispatchQueue?,
                             success: APISuccess,
                             failure: APIFailure,
                             progress: ProgressBlock? = nil) -> Moya.Cancellable {
        let target = MultiTarget.target(api)
        
        return base.request(target, callbackQueue: queue, progress: progress, completion: { result in
            guard let plugins = base.plugins as? APIPlugins else {
                /// 主线程回调
                JJMainAsync {
                    Self.handleResponse(result, nil, isParser: api.isParser, success: success, failure: failure, progress: progress)
                }
                return
            }
            
            YMNetworkUtil.handyLastNeverPlugin(plugins, result: result, target: target) { tuple in
                if tuple.againRequest {
                    beginRequest(api, base: base, queue: queue, success: success, failure: failure, progress: progress)
                    return
                }
                /// 主线程回调
                JJMainAsync {
                    Self.handleResponse(tuple.result, tuple.mapResult, isParser: api.isParser, success: success, failure: failure, progress: progress)
                }
            }
        })
    }

    private static func handleResponse(_ result: MoyaResult, _ jsonResult: MapJSONResult?, isParser: Bool, success: APISuccess, failure: APIFailure, progress: ProgressBlock?) {
        guard let _jsonResult = jsonResult else {
            Self.handleResult(result, isParser: isParser, success: success, failure: failure, progress: progress)
            return
        }
        switch _jsonResult {
        case .success(let json):
            let json = JSON(rawValue: json) ?? JSON()
            let responseModel = YMResponse.init(json: json)
            success?(responseModel)
        case .failure(let error):
            failure?(YMResponse(json: JSON()), error)
        }
    }
    
    
    /// 结果
    /// - Parameters:
    ///   - isParser: 数据是否需要解析
    public static func handleResult(_ result: MoyaResult, isParser: Bool, success: APISuccess, failure: APIFailure, progress: ProgressBlock?) {
        switch result {
        case .success(let response):
            let json = JSON(response.data)
            let responseModel = YMResponse.init(json: json)
            if isParser {
                if responseModel.code == kHttpCodeSuccess {
                    success?(responseModel)
                }else {
                    failure?(responseModel, MoyaError.statusCode(response))
                }
                /// 直接进度拉满
                progress?(ProgressResponse(response: response))
                /*
                 do {
                 let _ = try response.filterSuccessfulStatusCodes()
                 success(responseModel)
                 } catch MoyaError.statusCode(let response) {
                 failure(responseModel, MoyaError.statusCode(response))
                 } catch MoyaError.jsonMapping(let response) {
                 failure(responseModel, MoyaError.jsonMapping(response))
                 } catch {
                 failure(responseModel, error)
                 }
                 */
            }else {
                success?(responseModel)
            }
        case .failure(let error):
            failure?(YMResponse(json: JSON()), error)
        }
    }

}
